/* Yijun Yu */
D           [0-9]
L           [a-zA-Z_]
H           [a-fA-F0-9]
E           [Ee][+-]?{D}+
FS          (f|F|l|L)
IS          (u|U|l|L)*
/* suggested by Sebastien Fricker */
%option prefix="yy" 
%option outfile="lex.yy.c"
%option noyywrap
%{
/* Yijun: in order for prefix to work */
#define LVAL yylval
#include <stdio.h>
#include "types.h"
#include "gram.tab.h"
#include "symtbl.h"
#include "symtbl.c"

void count();
%}

%%
"/*"            { comment(); }

"auto"          { count(); return(AUTO); }
"break"         { count(); return(BREAK); }
"case"          { count(); return(CASE); }
"char"          { count(); return(CHAR); }
"const"         { count(); return(CONST); }
"continue"      { count(); return(CONTINUE); }
"default"       { count(); return(DEFAULT); }
"do"            { count(); return(DO); }
"double"        { count(); return(DOUBLE); }
"else"          { count(); return(ELSE); }
"enum"          { count(); return(ENUM); }
"extern"        { count(); return(EXTERN); }
"float"         { count(); return(FLOAT); }
"for"           { count(); return(FOR); }
"goto"          { count(); return(GOTO); }
"if"            { count(); return(IF); }
"int"           { count(); return(INT); }
"long"          { count(); return(LONG); }
"register"      { count(); return(REGISTER); }
"return"        { count(); return(RETURN); }
"short"         { count(); return(SHORT); }
"signed"        { count(); return(SIGNED); }
"sizeof"        { count(); return(SIZEOF); }
"static"        { count(); return(STATIC); }
"struct"        { count(); return(STRUCT); }
"switch"        { count(); return(SWITCH); }
"typedef"       { count(); return(TYPEDEF); }
"union"         { count(); return(UNION); }
"unsigned"      { count(); return(UNSIGNED); }
"void"          { count(); return(VOID); }
"volatile"      { count(); return(VOLATILE); }
"while"         { count(); return(WHILE); }

{L}({L}|{D})*       { count(); return(check_type()); }

0[xX]{H}+{IS}?      { count(); return(CONSTANT); }
0{D}+{IS}?      { count(); return(CONSTANT); }
{D}+{IS}?       { count(); return(CONSTANT); }
'(\\.|[^\\'])+'     { count(); return(CONSTANT); }

{D}+{E}{FS}?        { count(); return(CONSTANT); }
{D}*"."{D}+({E})?{FS}?  { count(); return(CONSTANT); }
{D}+"."{D}*({E})?{FS}?  { count(); return(CONSTANT); }

\"(\\.|[^\\"])*\"   { count(); return(STRING_LITERAL); }

">>="           { count(); return(RIGHT_ASSIGN); }
"<<="           { count(); return(LEFT_ASSIGN); }
"+="            { count(); return(ADD_ASSIGN); }
"-="            { count(); return(SUB_ASSIGN); }
"*="            { count(); return(MUL_ASSIGN); }
"/="            { count(); return(DIV_ASSIGN); }
"%="            { count(); return(MOD_ASSIGN); }
"&="            { count(); return(AND_ASSIGN); }
"^="            { count(); return(XOR_ASSIGN); }
"|="            { count(); return(OR_ASSIGN); }
">>"            { count(); return(RIGHT_OP); }
"<<"            { count(); return(LEFT_OP); }
"++"            { count(); return(INC_OP); }
"--"            { count(); return(DEC_OP); }
"->"            { count(); return(PTR_OP); }
"&&"            { count(); return(AND_OP); }
"||"            { count(); return(OR_OP); }
"<="            { count(); return(LE_OP); }
">="            { count(); return(GE_OP); }
"=="            { count(); return(EQ_OP); }
"!="            { count(); return(NE_OP); }
";"         { count(); return(PUNCT_SEMICOLON); }
"{"         { count(); return(PUNCT_LBRACE); }
"}"         { count(); return(PUNCT_RBRACE); }
","         { count(); return(PUNCT_COMMA); }
":"         { count(); return(PUNCT_COLON); }
"="         { count(); return(PUNCT_EQUAL); }
"("         { count(); return(PUNCT_LPAR); }
")"         { count(); return(PUNCT_RPAR); }
"["         { count(); return(PUNCT_LBRACKET); }
"]"         { count(); return(PUNCT_RBRACKET); }
"."         { count(); return(PUNCT_DOT); }
"&"         { count(); return(PUNCT_AMBLE); }
"!"         { count(); return(PUNCT_EXCLAIM); }
"~"         { count(); return(PUNCT_TILDE); }
"-"         { count(); return(PUNCT_MINUS); }
"+"         { count(); return(PUNCT_PLUS); }
"*"         { count(); return(PUNCT_STAR); }
"/"         { count(); return(PUNCT_DIV); }
"%"         { count(); return(PUNCT_PERCENT); }
"<"         { count(); return(PUNCT_LT); }
">"         { count(); return(PUNCT_GT); }
"^"         { count(); return(PUNCT_CARET); }
"|"         { count(); return(PUNCT_OR); }
"?"         { count(); return(PUNCT_QUESTION); }

[ \t\v\n\f]     { count(); }
.           { /* ignore bad characters */ }

%%
comment()
{
    char c, c1;

loop:
    while ((c = input()) != '*' && c != 0)
        putchar(c);

    if ((c1 = input()) != '/' && c != 0)
    {
        unput(c1);
        goto loop;
    }

    if (c != 0)
        putchar(c1);
}

int column = 0;

void count()
{
    int i;

    for (i = 0; yytext[i] != '\0'; i++)
        if (yytext[i] == '\n')
            column = 0;
        else if (yytext[i] == '\t')
            column += 8 - (column % 8);
        else
            column++;

    ECHO;
}


int check_type()
{
  long i,j;
  struct SymbolTableNode *p;
  j = Lookup(yytext);
  p = (struct SymbolTableNode *) j;
  if (j == 0) {
       j = Insert(yytext);
       p = (struct SymbolTableNode *) j;
       p->count = 1;
  } else
       p->count = (p->count) + 1;
  /* see if we've got a typedef name*/
  LVAL.info.symptr = p;
  if (p->symtype) {
	    return TYPE_NAME;
  } 
  return(IDENTIFIER);
}
